'''
Created on 29/04/2013

@author: mirta
'''
from datetime import date

from flask import Blueprint
from flask import request
from flask import render_template
from flask import flash
from flask import redirect
from flask import url_for
from flask import current_app

from app import db

from app.security import g
from app.security import permission

from app.wtforms.relacion_forms import RelacionBuscar
from app.wtforms.relacion_forms import RelacionEditable

from app.models.item import Item
from app.models.fase import Fase
from app.models.linea_base import LineaBase
from app.models.historial import Historial
from app.models.permiso import Permiso


mod = Blueprint('relaciones', __name__, url_prefix='/relacion')


@mod.route('/administracion/', methods=['GET', 'POST'])
@permission('ADMINISTRACION_RELACIONES')
def administracion_relacion():
       
    """
    Muestra en pantalla los items que existen en el proyecto con el cual se logueo el usuario.
    Si no recibe algun filtro como parametro, lista todos los items.
    Si recibe algun filtro, muestra los items que cumplen con el filtro indicado
    """
    if g.proyecto==None:
        flash('No tiene permiso para ver esta pagina.')
        return redirect(url_for('acceso.home'))
    
    #Obtenemos el proyecto seleccionado
    proyecto_seleccionado = g.proyecto
    
    # Obtenemos el formulario
    form =  RelacionBuscar(request.form)    
      
    # Obtenemos el filtro
    nombreFilter = form.nombre.data
    faseFilter = form.fase.data
    
    if(nombreFilter == None):
        nombreFilter = '' 
    if(faseFilter == None):
        faseFilter = ''  
    
    items = Item.query.filter(Item.nombre.like( '%'+nombreFilter+'%' ), Item.estado=='Activo').join(Fase).filter(Fase.nombre.like('%' + faseFilter + '%'), Fase.proyecto_id == proyecto_seleccionado.id)
    items = items.all()    
             
        
    return render_template('relacion/administracion_relacion.html', form = form, items = items)


@mod.route('/crear/<item>/', methods=['GET', 'POST'])
def crear_relacion(item):
    """
    Crea una relacion entre items, muestra todos lo items con los cuales el item seleccionado
    se puede relacionar actualmente
    @param item: id del item que se quiere relacionar
    """
    
    
    # Obtenemos el item seleccionado
    item_seleccionado = Item.query.filter_by(id=item).first()
    
    # Obtenemos la fase del item seleccionado
    fase_item_seleccionado = Fase.query.filter_by(id = item_seleccionado.fase.id).first()
    
    
    # Verificamos si el usuario tiene permisos para modificar los items de la fases
    if(verificar_autorizacion_fase(usuario=g.user, fase=fase_item_seleccionado, permisoRequerido='MODIFICAR')):
        
        #Obtenemos el proyecto seleccionado
        proyecto_seleccionado = g.proyecto
    
        if(proyecto_seleccionado.estado != 'Pendiente'):  
            
            flash('No se puede modificar los item del proyecto seleccionado')  
            return redirect(url_for('relaciones.administracion_relacion'))
        
        if(item_seleccionado.antecesor_id != None and item_seleccionado.padre_id != None):  
            
            flash('El item ya posee antecesor y padre')  
            return redirect(url_for('relaciones.administracion_relacion'))  
        
        
        # Obtenemos el formulario
        form =  RelacionEditable(request.form)
    
        #items =Item.query.all()
        lista_items = []
    
        # Si el item no pertecene a la fase 1 del proyecto y no posee un antecesor
        # obtenemos la fase anterior y la lineas bases de esa fase
        if item_seleccionado.fase.posicion > 1 and item_seleccionado.antecesor_id==None:
            fase = Fase.query.filter_by(proyecto_id=proyecto_seleccionado.id, posicion=item_seleccionado.fase.posicion - 1).first()
            lb = LineaBase.query.filter_by(fase_id=fase.id)
            lb = lb.all()
        
            # Si existen lineas bases en esa fase
            if lb!=None:
                # Recorremos cada linea base y preguntamos si su estado es Cerrada, si es asi
                # obtenemos los items de las lineas base para una relacion antecesor - sucesor
                for lb_ind in lb:
                    if lb_ind.estado=='Abierta':
                        items_lb = Item.query.filter_by(linea_base_id=lb_ind.id)
                        items_lb = items_lb.all()
                    
                        # Si la lista de items de la linea base no es nula, agregamos a la opciones
                        # para crear la relacion
                        if items_lb != None:
                            for item_ind in items_lb:
                                nombre = item_ind.nombre + " " + item_ind.fase.nombre
                                lista_items.append((item_ind.id, nombre))
            
        # Obtenemos la fase de item que se selecciono para relacionar y obtenemos sus items
        # para una relacion padre-hijo
        fase_seleccionada = Fase.query.filter_by(proyecto_id=proyecto_seleccionado.id, id=item_seleccionado.fase.id).first()
        items = Item.query.filter_by(fase_id=fase_seleccionada.id)
        items = items.all()
    
        # Si el item seleccionado no posee un padre, obtenemos los items de su fase que no sea el mismo
        for item_ind in items:
            if (item_seleccionado.padre_id == None) and (item_ind!=item_seleccionado):
                item_padre = Item.query.filter_by(id=item_ind.padre_id).first()
                # Si el item no le tiene como padre al item seleccionado, lo agregamos en la lista de
                # opciones de items con quien relacionar
                if item_padre != item_seleccionado:
                    nombre = item_ind.nombre + " " + item_ind.fase.nombre
                    lista_items.append((item_ind.id, nombre))
        
        
        if(lista_items==[]):  
            flash('No existen items para relacionar')  
            return redirect(url_for('relaciones.administracion_relacion'))
        
        # Mostramos en la vista la lista total de los items permitidos        
        form.items.choices = lista_items
    
        # Realizamos la validacion de datos del formulario
        if form.validate_on_submit():
        
            # Obtenemos el item a relacionar
            item_a_relacionar = Item.query.filter_by(id=form.items.data[0]).first()
        
            # Si ambos items son de la misma fase, se establece una relacion padre-hijo
            if item_a_relacionar.fase_id == item_seleccionado.fase_id:
                # Guardamos en el historial de items los datos del items antes de ser relacionado
                historial_item = Historial()
                historial_item.setAntecesor(item_seleccionado.antecesor_id)
                historial_item.setComplejidad(item_seleccionado.complejidad)
                historial_item.setCosto(item_seleccionado.costo)
                historial_item.setDescripcion(item_seleccionado.descripcion)
                historial_item.setDuracion(item_seleccionado.duracion)
                historial_item.setEstado(item_seleccionado.estado)
                historial_item.setFase(item_seleccionado.fase)
                historial_item.setFechaCreacion(item_seleccionado.fecha_creacion)
                historial_item.setFechaModificacion(date.today())
                historial_item.setItemId(item_seleccionado.id)
                historial_item.setLb(item_seleccionado.linea_base)
                historial_item.setNombre(item_seleccionado.nombre)
                historial_item.setNumero(item_seleccionado.numero)
                historial_item.setObservacion(item_seleccionado.observacion)
                historial_item.setPadre(item_seleccionado.padre_id)
                historial_item.setPrioridad(item_seleccionado.prioridad)
                historial_item.setVersion(item_seleccionado.version)
                # Guardamos el nuevo registro
                db.session.add(historial_item)
                db.session.commit()
            
                # Seteamos el atributo padre del item
                item_seleccionado.setPadre(item_a_relacionar.id)
                # Actualizamos la version del item
                version = int(item_seleccionado.version) +1
                item_seleccionado.setVersion(version)
                # Guardamos los cambio
                db.session.add(item_seleccionado)
                db.session.commit()
            
            else:
                # Si ambos items no son de la misma fase
                # Guardamos en el historial de items los datos del items antes de ser relacionado
                historial_item = Historial()
                historial_item.setAntecesor(item_seleccionado.antecesor_id)
                historial_item.setComplejidad(item_seleccionado.complejidad)
                historial_item.setCosto(item_seleccionado.costo)
                historial_item.setDescripcion(item_seleccionado.descripcion)
                historial_item.setDuracion(item_seleccionado.duracion)
                historial_item.setEstado(item_seleccionado.estado)
                historial_item.setFase(item_seleccionado.fase)
                historial_item.setFechaCreacion(item_seleccionado.fecha_creacion)
                historial_item.setFechaModificacion(date.today())
                historial_item.setItemId(item_seleccionado.id)
                historial_item.setLb(item_seleccionado.linea_base)
                historial_item.setNombre(item_seleccionado.nombre)
                historial_item.setNumero(item_seleccionado.numero)
                historial_item.setObservacion(item_seleccionado.observacion)
                historial_item.setPadre(item_seleccionado.padre_id)
                historial_item.setPrioridad(item_seleccionado.prioridad)
                historial_item.setVersion(item_seleccionado.version)
                # Guardamos el nuevo registro
                db.session.add(historial_item)
                db.session.commit()
            
                # Seteamos el antecesor del item
                item_seleccionado.setAntecesor(item_a_relacionar.id)
                # Actualizamos la version del item
                version = int(item_seleccionado.version) +1
                item_seleccionado.setVersion(version)
                # Guardamos los cambios
                db.session.add(item_seleccionado)
                db.session.commit()
            
            flash('La relacion ha sido registrada con exito')     
            return redirect(url_for('relaciones.administracion_relacion'))   
                
        return render_template("relacion/crear_relacion.html", form=form, item=item)
    else:
        flash('NO TIENE PERMISOS PARA MODIFICAR LA FASE SELECCIONADA') 
        return redirect(url_for('relaciones.administracion_relacion'))


@mod.route('/eliminar/<item>/', methods=['GET', 'POST'])
def eliminar_relacion(item): 
    """
    Elimina una relacion entre items, muestra todos lo items con los cuales el item 
    seleccionado tiene una relacion actualmente
    @param item: id del item que se quiere relacionar
    """   
    #Obtenemos el proyecto seleccionado
    proyecto_seleccionado = g.proyecto
    
     
    
    # Obtenemos la fase del item seleccionado
    fase_item_seleccionado = Fase.query.filter_by(proyecto_id = proyecto_seleccionado.id).first()
    current_app.logger.info(fase_item_seleccionado)
    
    # Verificamos si el usuario tiene permisos para modificar los items de la fases
    if(verificar_autorizacion_fase(g.user, fase_item_seleccionado, 'MODIFICAR')):
    
        if(proyecto_seleccionado.estado != 'Pendiente'):  
            
            flash('No se puede modificar los item del proyecto seleccionado')  
            return redirect(url_for('relaciones.administracion_relacion'))
        
        # Obtenemos el item seleccionado
        item_seleccionado = Item.query.filter_by(id=item).first()
    
        # Obtenemos el formulario
        form =  RelacionEditable(request.form)
    
        items = []
        # Obtenemos el padre y el antecesor del item selecionado
        items.append( Item.query.filter_by(id=item_seleccionado.padre_id).first())
        items.append( Item.query.filter_by(id=item_seleccionado.antecesor_id).first())
    
        #Los procesamos para mostrar en la vista
        lista_items = []
        for item_ind in items:
            if item_ind!=None:
                nombre = item_ind.nombre + " " + item_ind.fase.nombre
                lista_items.append((item_ind.id, nombre))
        
        if(lista_items==[]):  
            flash('No existen items relacionados')  
            return redirect(url_for('relaciones.administracion_relacion'))
        
        # Mostramos la lista de items con los cuales esta relacionado el item
        form.items.choices = lista_items    
    
        # Validamos los datos ingresado en el formulario
        if form.validate_on_submit():
        
            # Obtenemos el item con el cual se desea eliminar la relacion
            item_a_desrelacionar = Item.query.filter_by(id=form.items.data[0]).first()
        
            # Si ambos items son de la misma fase, se rompe una relacion padre-hijo
            if item_a_desrelacionar.fase_id == item_seleccionado.fase_id:
                # Guardamos en el historial de items los datos del item antes de ser modificado
                historial_item = Historial()
                historial_item.setAntecesor(item_seleccionado.antecesor_id)
                historial_item.setComplejidad(item_seleccionado.complejidad)
                historial_item.setCosto(item_seleccionado.costo)
                historial_item.setDescripcion(item_seleccionado.descripcion)
                historial_item.setDuracion(item_seleccionado.duracion)
                historial_item.setEstado(item_seleccionado.estado)
                historial_item.setFase(item_seleccionado.fase)
                historial_item.setFechaCreacion(item_seleccionado.fecha_creacion)
                historial_item.setFechaModificacion(date.today())
                historial_item.setItemId(item_seleccionado.id)
                historial_item.setLb(item_seleccionado.linea_base)
                historial_item.setNombre(item_seleccionado.nombre)
                historial_item.setNumero(item_seleccionado.numero)
                historial_item.setObservacion(item_seleccionado.observacion)
                historial_item.setPadre(item_seleccionado.padre_id)
                historial_item.setPrioridad(item_seleccionado.prioridad)
                historial_item.setVersion(item_seleccionado.version)
                # Guardamos el nuevo registro
                db.session.add(historial_item)
                db.session.commit()
            
                # Eliminamos el padre del item
                item_seleccionado.setPadre(None)
                # Actualizamos la version del item
                version = int(item_seleccionado.version) +1
                item_seleccionado.setVersion(version)
                # Guardamos la actualizacion
                db.session.add(item_seleccionado)
                db.session.commit()
            
            else:
                # Si ambos items son de fases distintas se rompe una relacion antecesor-sucesor
                # Guardamos en el historial de items los datos del item antes de ser modificad
                historial_item = Historial()
                historial_item.setAntecesor(item_seleccionado.antecesor_id)
                historial_item.setComplejidad(item_seleccionado.complejidad)
                historial_item.setCosto(item_seleccionado.costo)
                historial_item.setDescripcion(item_seleccionado.descripcion)
                historial_item.setDuracion(item_seleccionado.duracion)
                historial_item.setEstado(item_seleccionado.estado)
                historial_item.setFase(item_seleccionado.fase)
                historial_item.setFechaCreacion(item_seleccionado.fecha_creacion)
                historial_item.setFechaModificacion(date.today())
                historial_item.setItemId(item_seleccionado.id)
                historial_item.setLb(item_seleccionado.linea_base)
                historial_item.setNombre(item_seleccionado.nombre)
                historial_item.setNumero(item_seleccionado.numero)
                historial_item.setObservacion(item_seleccionado.observacion)
                historial_item.setPadre(item_seleccionado.padre_id)
                historial_item.setPrioridad(item_seleccionado.prioridad)
                historial_item.setVersion(item_seleccionado.version)
                # Guardamos el nuevo registro
                db.session.add(historial_item)
                db.session.commit()
            
                # Eliminamos el antecesor del item
                item_seleccionado.setAntecesor(None)
                # Actualizamos la version del item
                version = int(item_seleccionado.version) +1
                item_seleccionado.setVersion(version)
                # Guardamos la actualizacion
                db.session.add(item_seleccionado)
                db.session.commit()
            
            flash('La relacion ha sido eliminada con exito')     
            return redirect(url_for('relaciones.administracion_relacion')) 
    
        return render_template("relacion/eliminar_relacion.html", form=form, item=item)
    else:
        flash('NO TIENE PERMISOS PARA MODIFICAR LA FASE SELECCIONADA') 
        return redirect(url_for('relaciones.administracion_relacion'))
    

def verificar_autorizacion_fase(usuario = None, fase = None, permisoRequerido = None):
    """
    Verifica que el usuario posea pemisos para realizar una operacion determinada sobre una
    fase
    @param usuario: usuario que se logueo
    @param fase: fase sobre la cual se desea realizar una operacion
    @param permisoRequerido: permiso que debe poseer el usuario sobre la fase para que pueda
    realizar la acccion
    """
    
    autorizado = False
    
    #============================================================================
    #  rolAdministrador = db.session.query(Rol).filter_by(nombre = 'Administrador de Sistema').first()
    # 
    #  if rolAdministrador in usuario.roles:
    #          autorizado = True
    #          
    #  else:         
    #============================================================================
    permiso = db.session.query(Permiso).filter_by(nombre = permisoRequerido, entidad_id = fase.entidad_id).first()
    # flash(permiso)
    if(permiso != None):
        for rol in usuario.roles:
            if permiso in rol.permiso:
                autorizado = True
    
    return autorizado